import requests
import time
import json
import logging
import easytrader
import os
import pandas as pd
from datetime import datetime, time as dt_time

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("signal_client.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# 服务器地址
SERVER_URL='http://{你的服务器IP地址}:5000'

# 同花顺路径
THS_PATH = r"C:\同花顺软件\同花顺\xiadan.exe"

# 已处理信号的文件名
PROCESSED_SIGNALS_FILE = 'processed_signals.csv'

def connect_to_ths():
    """连接到同花顺交易客户端"""
    try:
        user = easytrader.use('universal_client')
        user.connect(THS_PATH)
        logger.info("成功连接到同花顺交易客户端")
        return user
    except Exception as e:
        logger.error(f"连接同花顺失败: {str(e)}")
        return None

def get_signals_from_server():
    """从服务器获取信号"""
    try:
        response = requests.get(f"{SERVER_URL}/get_signals")
        if response.status_code == 200:
            return response.json()
        else:
            logger.error(f"获取信号失败: {response.text}")
            return []
    except Exception as e:
        logger.error(f"获取信号时出错: {str(e)}")
        return []

def get_position(user, stock_code):
    """获取指定股票的持仓信息"""
    try:
        positions = user.position
        for pos in positions:
            if pos['证券代码'] == stock_code:
                return pos
        return None
    except Exception as e:
        logger.error(f"获取持仓信息时出错: {str(e)}")
        return None

def check_trade_result(user, entrust_no):
    """检查交易结果"""
    try:
        orders = user.today_entrusts
        for order in orders:
            if order['委托编号'] == entrust_no:
                return {
                    'status': order['交易状态'],
                    'order': order
                }
        return None
    except Exception as e:
        logger.error(f"检查交易结果时出错: {str(e)}")
        return None

def is_trading_time():
    """判断当前是否为交易时间"""
    now = datetime.now().time()
    morning_start = dt_time(9, 30)
    morning_end = dt_time(11, 30)
    afternoon_start = dt_time(13, 0)
    afternoon_end = dt_time(15, 0)
    
    return (morning_start <= now <= morning_end) or (afternoon_start <= now <= afternoon_end)

def execute_trade(user, signal):
    """执行交易"""
    try:
        action = 'buy' if signal.get('买卖') == 'True' else 'sell'
        security = signal.get('股票代码')
        price = float(signal.get('平均成交价格', 0))
        amount = int(signal.get('下单数量', 0))
        
        if not security:
            logger.error("信号中缺少股票代码")
            return False
            
        # 将聚宽的股票代码转换为同花顺格式
        # 例如: 000001.XSHE -> 000001
        stock_code = security.split('.')[0]
        
        # 获取当前持仓
        position = get_position(user, stock_code)
        current_amount = int(position['可用余额']) if position else 0
        
        if action == 'buy':
            # 检查资金是否足够
            balance = user.balance
            available_cash = float(balance['可用金额'])
            required_cash = price * amount
            
            if required_cash > available_cash:
                logger.error(f"可用资金不足，需要: {required_cash}, 可用: {available_cash}")
                return False
                
            logger.info(f"执行买入: {stock_code}, 价格: {price}, 数量: {amount}")
            result = user.buy(stock_code, price=price, amount=amount)
            
        elif action == 'sell':
            # 检查持仓是否足够
            if current_amount < amount:
                logger.error(f"持仓不足，需要: {amount}, 可用: {current_amount}")
                return False
                
            logger.info(f"执行卖出: {stock_code}, 价格: {price}, 数量: {amount}")
            result = user.sell(stock_code, price=price, amount=amount)
            
        else:
            logger.warning(f"未知交易类型: {action}")
            return False
        
        logger.info(f"交易结果: {result}")
        return True
    except Exception as e:
        logger.error(f"执行交易时出错: {str(e)}")
        return False

def save_signals_to_csv(signals):
    """将信号保存到CSV文件"""
    try:
        # 创建DataFrame
        df = pd.DataFrame(signals)
        
        # 生成文件名，包含时间戳
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f'signals_{timestamp}.csv'
        
        # 保存到CSV文件
        df.to_csv(filename, index=False, encoding='utf-8-sig')
        logger.info(f"信号数据已保存到文件: {filename}")
        return True
    except Exception as e:
        logger.error(f"保存信号数据到CSV时出错: {str(e)}")
        return False

def load_processed_signals():
    """加载已处理的信号"""
    try:
        if os.path.exists(PROCESSED_SIGNALS_FILE):
            df = pd.read_csv(PROCESSED_SIGNALS_FILE)
            return set(df['signal_id'].tolist())
        return set()
    except Exception as e:
        logger.error(f"加载已处理信号时出错: {str(e)}")
        return set()

def save_processed_signal(signal_id):
    """保存已处理的信号"""
    try:
        # 创建新的DataFrame
        new_signal = pd.DataFrame({
            'signal_id': [signal_id],
            'processed_time': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')]
        })
        
        # 如果文件存在，追加数据；如果不存在，创建新文件
        if os.path.exists(PROCESSED_SIGNALS_FILE):
            new_signal.to_csv(PROCESSED_SIGNALS_FILE, mode='a', header=False, index=False)
        else:
            new_signal.to_csv(PROCESSED_SIGNALS_FILE, index=False)
            
        logger.info(f"已处理信号已保存: {signal_id}")
        return True
    except Exception as e:
        logger.error(f"保存已处理信号时出错: {str(e)}")
        return False

def check_daily_trades(user):
    """检查当日所有交易结果"""
    try:
        # 获取当日所有委托
        orders = user.today_entrusts
        if not orders:
            logger.info("今日没有交易委托")
            return
            
        # 创建结果DataFrame
        results = []
        for order in orders:
            result = {
                '委托编号': order['委托编号'],
                '股票代码': order['证券代码'],
                '交易类型': order['交易类型'],
                '委托价格': order['委托价格'],
                '委托数量': order['委托数量'],
                '交易状态': order['交易状态'],
                '成交数量': order['成交数量'],
                '成交均价': order['成交均价'],
                '委托时间': order['委托时间']
            }
            results.append(result)
            
        # 保存到CSV文件
        df = pd.DataFrame(results)
        filename = f'trade_results_{datetime.now().strftime("%Y%m%d")}.csv'
        df.to_csv(filename, index=False, encoding='utf-8-sig')
        logger.info(f"当日交易结果已保存到: {filename}")
        
        # 统计交易结果
        total_orders = len(results)
        success_orders = len([r for r in results if r['交易状态'] == '已成'])
        logger.info(f"当日委托总数: {total_orders}, 成功成交: {success_orders}")
        
    except Exception as e:
        logger.error(f"检查当日交易结果时出错: {str(e)}")

def main():
    """主函数"""
    # 连接到同花顺
    user = connect_to_ths()
    if not user:
        logger.error("无法连接到同花顺，程序退出")
        return
    
    # 加载已处理的信号
    processed_signals = load_processed_signals()
    logger.info(f"已加载 {len(processed_signals)} 个已处理信号")
    
    # 获取并显示当前账户信息
    try:
        balance = user.balance
        logger.info(f"账户资金信息: {balance}")
        positions = user.position
        logger.info(f"当前持仓信息: {positions}")
    except Exception as e:
        logger.error(f"获取账户信息时出错: {str(e)}")
    
    logger.info("开始监控服务器信号...")
    
    # 存储待执行的信号
    pending_signals = []
    
    while True:
        try:
            current_time = datetime.now()
            
            # 获取信号（无论是否在交易时间都获取）
            signals = get_signals_from_server()
            if signals:
                save_signals_to_csv(signals)
                # 将新信号添加到待执行列表
                for signal in signals:
                    signal_id = f"{signal.get('订单添加时间')}_{signal.get('股票代码')}_{signal.get('买卖')}"
                    if signal_id not in processed_signals and signal not in pending_signals:
                        pending_signals.append(signal)
                        logger.info(f"添加新信号到待执行列表: {signal}")
            
            # 如果是交易时间，执行待执行的信号
            if is_trading_time() and pending_signals:
                logger.info(f"当前有 {len(pending_signals)} 个待执行信号")
                # 复制一份待执行信号列表，避免在遍历时修改
                signals_to_execute = pending_signals.copy()
                
                for signal in signals_to_execute:
                    signal_id = f"{signal.get('订单添加时间')}_{signal.get('股票代码')}_{signal.get('买卖')}"
                    logger.info(f"执行待处理信号: {signal}")
                    
                    # 执行交易
                    entrust_no = execute_trade(user, signal)
                    if entrust_no:
                        processed_signals.add(signal_id)
                        save_processed_signal(signal_id)
                        pending_signals.remove(signal)  # 从待执行列表中移除
                        logger.info(f"信号处理成功: {signal_id}")
                    else:
                        logger.error(f"信号处理失败: {signal_id}")
            
            # 如果是收盘时间（15:00后），检查当日交易结果
            elif current_time.hour >= 15:
                check_daily_trades(user)
                # 清空待执行信号列表
                pending_signals.clear()
                # 等待到第二天
                time.sleep(3600)  # 休眠1小时
                continue
            
            # 每10秒检查一次
            time.sleep(10)
            
        except KeyboardInterrupt:
            logger.info("程序被用户中断")
            break
        except Exception as e:
            logger.error(f"运行时出错: {str(e)}")
            time.sleep(30)  # 出错后等待30秒再重试

if __name__ == "__main__":
    main()